package com.example.backblog.util;

import cn.hutool.core.io.FileUtil;
import cn.novelweb.tool.http.Result;
import cn.novelweb.tool.upload.file.FileInfo;
import cn.novelweb.tool.upload.local.pojo.UploadFileParam;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;

import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.text.SimpleDateFormat;
import java.util.LinkedList;
import java.util.List;

public class MyLocalUpload {
    private static final Logger log = LoggerFactory.getLogger(cn.novelweb.tool.upload.local.LocalUpload.class);
    public static String defaultPath;

    public MyLocalUpload() {
    }

    public static Result<?> checkFileMd5(String fileMd5, String fileName, String confFilePath, String tmpFilePath) throws Exception {
        boolean isParamEmpty = StringUtils.isBlank(fileMd5) || StringUtils.isBlank(fileName) || StringUtils.isBlank(confFilePath) || StringUtils.isBlank(tmpFilePath);
        if (isParamEmpty) {
            throw new Exception("参数值为空");
        } else {
            File confFile = new File(confFilePath + File.separatorChar + fileName + ".conf");
            boolean isTmpFileEmpty = (new File(tmpFilePath + File.separatorChar + fileName + "_tmp")).exists();
            if (confFile.exists() && isTmpFileEmpty) {
                byte[] completeList = FileUtils.readFileToByteArray(confFile);
                List<String> missChunkList = new LinkedList();

                for(int i = 0; i < completeList.length; ++i) {
                    if (completeList[i] != 127) {
                        missChunkList.add(Integer.toString(i));
                    }
                }

                JSONArray jsonArray = JSON.parseArray(JSONObject.toJSONString(missChunkList));
                return Result.ok(HttpStatus.PARTIAL_CONTENT.value(), "文件已经上传了一部分", jsonArray);
            } else {
                boolean isFileEmpty = (new File(tmpFilePath + File.separatorChar + fileName)).exists();
                return isFileEmpty && confFile.exists() ? Result.ok(HttpStatus.OK.value(), "文件已上传成功") : Result.ok(HttpStatus.NOT_FOUND.value(), "文件不存在");
            }
        }
    }

    public static Result<?> checkFileMd5(String fileMd5, String fileName) throws Exception {
        return checkFileMd5(fileMd5, fileName, defaultPath + File.separatorChar + fileMd5, defaultPath + File.separatorChar + fileMd5);
    }

    public static synchronized Result<?> fragmentFileUploader(UploadFileParam param, String confFilePath, String filePath, long chunkSize, HttpServletRequest request) throws Exception {
        boolean isParamEmpty = StringUtils.isBlank(filePath) || StringUtils.isBlank(confFilePath) && param.getFile() == null;
        if (isParamEmpty) {
            throw new Exception("参数值为空");
        } else {
            boolean isMultipart = ServletFileUpload.isMultipartContent(request);
            if (!isMultipart) {
                throw new IllegalArgumentException("上传内容不是有效的multipart/form-data类型.");
            } else {
                try {
                    File confFile = FileUtil.file(FileUtil.mkdir(confFilePath), String.format("%s.conf", param.getName()));
                    RandomAccessFile accessConfFile = new RandomAccessFile(confFile, "rw");
                    accessConfFile.setLength((long)param.getChunks());
                    accessConfFile.seek((long)param.getChunk());
                    accessConfFile.write(127);
                    accessConfFile.close();
                    File tmpFile = FileUtil.file(FileUtil.mkdir(filePath), String.format("%s_tmp", param.getName()));
                    RandomAccessFile accessTmpFile = new RandomAccessFile(tmpFile, "rw");
                    long offset = chunkSize * (long)param.getChunk();
                    accessTmpFile.seek(offset);
                    accessTmpFile.write(param.getFile().getBytes());
                    accessTmpFile.close();
                    byte[] completeList = FileUtils.readFileToByteArray(confFile);
                    byte isComplete = 127;

                    for(int i = 0; i < completeList.length && isComplete == 127; ++i) {
                        isComplete &= completeList[i];
                    }

                    if (isComplete != 127) {
                        return Result.ok(HttpStatus.OK.value(), "文件上传成功");
                    } else {
                        boolean isSuccess = renameFile(filePath,tmpFile, param.getName());
                        if (!isSuccess) {
                            throw new Exception("文件重命名时失败");
                        } else {
                            FileInfo fileInfo = FileInfo.builder().hash(param.getMd5()).name(param.getName()).type(param.getFile().getContentType()).path(tmpFile.getParent() + File.separatorChar + param.getName()).createTime(System.currentTimeMillis()).build();
                            return Result.ok(HttpStatus.CREATED.value(), "文件上传完成", fileInfo);
                        }
                    }
                } catch (IOException var18) {
                    var18.printStackTrace();
                    return Result.error("文件上传失败");
                }
            }
        }
    }

    public static Result<?> fragmentFileUploader(UploadFileParam param, long chunkSize, HttpServletRequest request) throws Exception {
        return fragmentFileUploader(param, defaultPath + File.separatorChar + param.getMd5(), defaultPath + File.separatorChar + param.getMd5(), chunkSize, request);
    }

    public static Result<?> regularFileUploader(UploadFileParam param, String filePath) throws Exception {
        boolean isParamEmpty = StringUtils.isBlank(filePath) || StringUtils.isBlank(param.getName()) && param.getFile() == null;
        if (isParamEmpty) {
            throw new Exception("参数值为空");
        } else {
            File uploadFolder = new File(filePath);
            if (!uploadFolder.exists() && !uploadFolder.mkdirs()) {
                return Result.fail(HttpStatus.FORBIDDEN.value(), "上传所需文件夹创建失败");
            } else {
                File uploadFile = new File(filePath + File.separatorChar + param.getName());
                param.getFile().transferTo(uploadFile);
                if (uploadFile.length() != param.getFile().getSize()) {
                    return Result.error("文件上传失败");
                } else {
                    FileInfo fileInfo = FileInfo.builder().hash(param.getMd5()).name(param.getName()).type(param.getFile().getContentType()).path(uploadFile.getPath()).createTime(System.currentTimeMillis()).build();
                    return Result.ok(HttpStatus.CREATED.value(), "文件上传完成", fileInfo);
                }
            }
        }
    }

    public static Result<?> regularFileUploader(UploadFileParam param) throws Exception {
        boolean isParamEmpty = StringUtils.isBlank(param.getName()) && param.getFile() == null;
        if (isParamEmpty) {
            throw new Exception("参数值为空");
        } else {
            param.setName(System.currentTimeMillis() + param.getName().substring(param.getName().lastIndexOf(".")));
            SimpleDateFormat simpleDateFormat = new SimpleDateFormat(String.format("yyyy%sMM%sdd", File.separatorChar, File.separatorChar));
            return regularFileUploader(param, defaultPath + File.separatorChar + simpleDateFormat.format(System.currentTimeMillis()));
        }
    }

    private static boolean renameFile(String filePath, File toBeRenamed, String toFileNewName) {
        if (toBeRenamed.exists() && !toBeRenamed.isDirectory()) {
            System.out.println(toBeRenamed.getParent());
            File newFile = new File(filePath + File.separatorChar + toFileNewName);
            return toBeRenamed.renameTo(newFile);
        } else {
            return false;
        }
    }

    static {
        defaultPath = String.format("log%suploader", File.separatorChar);
    }
}